﻿using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using System.ComponentModel;
using System.Xml.Linq;

namespace EasyXaf.LowCode.WorkflowEditors.Models.Activities;

[DomainComponent]
public abstract class Activity : FlowObject, IActivity
{
    public static IEnumerable<ITypeInfo> ActivityTypeInfos { get; }

    [Browsable(false)]
    public virtual string Caption
    {
        get => GetPropertyValue<string>();
        set => SetPropertyValue(value);
    }

    [Browsable(false)]
    public virtual string Comment
    {
        get => GetPropertyValue<string>();
        set => SetPropertyValue(value);
    }

    [Browsable(false)]
    public virtual string ImageName => "WF_Default";

    [Browsable(false)]
    public virtual string Color => "#2980B9";

    [Browsable(false)]
    public NodeViewMode ViewMode
    {
        get => GetPropertyValue<NodeViewMode>();
        set => SetPropertyValue(value);
    }

    [Browsable(false)]
    public double TitleViewScale
    {
        get => GetPropertyValue<double>();
        set => SetPropertyValue(value);
    }

    [Browsable(false)]
    public double DetailViewScale
    {
        get => GetPropertyValue<double>();
        set => SetPropertyValue(value);
    }

    [Browsable(false)]
    public virtual bool HasDetailView => false;

    [Browsable(false)]
    public bool IsSelected
    {
        get => Workflow.SelectedActivityId == Id;
        set => Workflow.SelectedActivityId = Id;
    }

    [Browsable(false)]
    public virtual bool AllowSelect => true;

    [Browsable(false)]
    public virtual bool AllowMove => true;

    [Browsable(false)]
    public virtual bool AllowScale => true;

    [Browsable(false)]
    public virtual bool AllowCopy => true;

    [Browsable(false)]
    public virtual bool AllowDelete => true;

    [Browsable(false)]
    public virtual bool AllowValidate => true;

    [Browsable(false)]
    public ISequence Sequence { get; }

    [Browsable(false)]
    public IContainer Container
    {
        get
        {
            if (Sequence is IBranch branch)
            {
                return ((INode)branch).Container;
            }
            else if (Sequence is IContainer container)
            {
                return container;
            }
            return null;
        }
    }

    [Browsable(false)]
    public IWorkflow Workflow { get; }

    public event EventHandler<bool> SelectionChanged;

    public Activity(IWorkflow workflow, ISequence sequence)
    {
        Workflow = workflow;
        Sequence = sequence;
        TitleViewScale = 1.0;
        DetailViewScale = 2.0;
    }

    static Activity()
    {
        ActivityTypeInfos = XafTypesInfo.Instance.PersistentTypes
            .Where(t => typeof(IActivity).IsAssignableFrom(t.Type))
            .Where(t => !t.IsAbstract && !t.IsInterface)
            .Where(t => t.Type.GetConstructor(new Type[] { typeof(IWorkflow), typeof(ISequence) }) != null)
            .ToList();
    }

    protected virtual void OnSelectionChanged(bool selected)
    {
        SelectionChanged?.Invoke(this, selected);
    }

    protected override void OnPropertyChanged(string propertyName)
    {
        base.OnPropertyChanged(propertyName);
        if (propertyName == nameof(IsSelected))
        {
            OnSelectionChanged(IsSelected);
        }
    }

    public override void WriteToXml(XElement element)
    {
        base.WriteToXml(element);

        SetXmlValue(element, nameof(Caption), Caption);
        SetCDataXmlValue(element, nameof(Comment), Comment);
        SetXmlValue(element, nameof(ViewMode), ViewMode);
        SetXmlValue(element, nameof(TitleViewScale), TitleViewScale);
        SetXmlValue(element, nameof(DetailViewScale), DetailViewScale);
    }

    public override void ReadFromXml(XElement element)
    {
        base.ReadFromXml(element);

        Caption = GetXmlValue<string>(element, nameof(Caption));
        Comment = GetXmlValue<string>(element, nameof(Comment));
        ViewMode = GetXmlValue<NodeViewMode>(element, nameof(ViewMode));
        TitleViewScale = GetXmlValue<double>(element, nameof(TitleViewScale));
        DetailViewScale = GetXmlValue<double>(element, nameof(DetailViewScale));
    }
}
